package com.example.sendmessage.server.core;

import com.example.sendmessage.common.MqException;

public class Router {
    /**
     *  检查交换机绑定关键字是否符合规则
     * @param bindingKey 绑定关键字
     * @return 是否符合规则
     */
    public boolean checkBindingKey(String bindingKey) {
        if (bindingKey.length() == 0) {
            // 交换机可以不添加绑定关系
            return true;
        }
        // 对绑定关键字逐个分析，查看是否符合规则
        for (int i = 0; i < bindingKey.length(); i++) {
            char ch = bindingKey.charAt(i);
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= '0' && ch <= '9') {
                continue;
            }
            if (ch == '.' || ch == '*' || ch == '#' || ch == '_') {
                continue;
            }
            return false;
        }
        // 查看* # 是否独立
        String[] words = bindingKey.split("\\.");
        for (String word : words) {
            if (word.length() > 1 && (word.contains("#") || word.contains("*"))) {
                return false;
            }
        }
        // 约定* # 的出现规则
        for (int i = 0; i < words.length - 1; i++) {
            if (words[i].equals("#") && words[i+1].equals("#")) {
                return false;
            }
            if (words[i].equals("#") && words[i+1].equals("*")) {
                return false;
            }
            if (words[i].equals("*") && words[i+1].equals("#")) {
                return false;
            }
        }
        return true;
    }

    /**
     * 路由是否合法
     * 数字 字母 _ .
     * @param routingKey 路由关键字
     * @return 是否合格
     */
    public boolean checkRoutingKey(String routingKey) {
        if (routingKey == null || routingKey.length() == 0) {
            // direct fanout交换机可以不需要路由
            return true;
        }
        for (int i = 0; i < routingKey.length(); i++){
            char ch = routingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z'){
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }
            if (ch >= '0' && ch <= '9'){
                continue;
            }
            if (ch == '_' || ch == '.') {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * 根据路由规则判断消息是否需要被转发
     * @param type 交换机类型
     * @param binding 获取bindingKey
     * @param message 获取routingKey
     * @return 是否需要转发
     * @throws MqException 交换机类型异常
     */
    public boolean route(ExchangeType type, Binding binding, Message message) throws MqException {
        if (type == ExchangeType.FANOUT) {
            return true;
        } else if (type == ExchangeType.TOPIC){
            // 根据匹配算法将routingKey与bindingKey进行匹配
            return routeTopic(binding, message);
        } else {
            throw new MqException("[Router] 不支持的交换机类型！exchangeName = "+ binding.getExchangeName());
        }
    }

    /**
     * routingKey 与 bindingKey的匹配算法
     * #表示匹配后面所有，*表示匹配一个字段
     */
    private boolean routeTopic(Binding binding, Message message) {
        // 匹配算法，双指针
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");
        int bindingIndex = 0;
        int routingIndex = 0;
        while (bindingIndex < bindingTokens.length && routingIndex < routingTokens.length) {
            if (bindingTokens[bindingIndex].equals("*")) {
                // *号直接跳过这个字段
                bindingIndex++;
                routingIndex++;
            } else if (bindingTokens[bindingIndex].equals("#")) {
                // #号是表示匹配后面所有
                bindingIndex++;
                if (bindingIndex >= bindingTokens.length) {
                    // bindingKey后面没有关键字了，匹配成功
                    return true;
                }
                // #号后面还有关键字，则需要判断routingKey中有没有对应的字段
                routingIndex = findNextIndex(routingTokens, routingIndex, bindingTokens[bindingIndex]);
                if (routingIndex == -1) {
                    return false;
                }
                // 看bindingKey后面是否还有字段，继续匹配
                bindingIndex++;
                routingIndex++;
            } else {
                // 普通匹配
                if (!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])) {
                    return false;
                }
                // 普通情况也要跳过
                bindingIndex++;
                routingIndex++;
            }
        }
        // 判断绑定字段与路由字段是否都匹配完毕
        return bindingIndex == bindingTokens.length && routingIndex ==  routingTokens.length;
    }

    /**
     * 返回路由的定位位置
     */
    private int findNextIndex(String[] routingTokens, int routingIndex, String bindingToken) {
        while (routingIndex < routingTokens.length) {
            if (routingTokens[routingIndex].equals(bindingToken)) {
                return routingIndex;
            }
            routingIndex++;
        }
        return -1;
    }
}
